import frappe
from frappe.utils import flt
from frappe.model.mapper import map_docs as old_map_docs


@frappe.whitelist()
def map_docs(method, source_names, target_doc, args=None):
    target_doc = old_map_docs(method, source_names, target_doc, args)
    """基于多张销售订单出货，实现以下功能
    1.物料明细行按料号，仓码，出货日期排序
    2.基于可用库存按顺序分配出货数量
    3.删除无可出数量物料行
    """
    items = target_doc.items if hasattr(target_doc, 'items') else None
    if method == "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note" and items:        
        #出货单明细行无delivery_date,通过销售订单明细主键从销售订单明细表获取出货日期
        so_item_names = [item.so_detail for item in items]        
        so_item_list = frappe.get_all("Sales Order Item", fields=['name','delivery_date'], filters ={'name': ('in', so_item_names)})
        #转成字典,方便后面vlookup
        delivery_date_dict = {so_item.name:so_item.delivery_date for so_item in so_item_list}
        for item in items:
            item.delivery_date = delivery_date_dict.get(item.so_detail)
        #排序
        items = sorted(items, key=lambda t:(t.item_code,t.warehouse, t.delivery_date))
        #遍历处理，相同物料号，仓库及可分配数量扣减
        item_code, warehouse, available_qty,conversion_factor = items[0].item_code,items[0].warehouse, items[0].actual_qty,items[0].conversion_factor or 1
        for item in items:
            if not (item.item_code == item_code and item.warehouse == warehouse):                
                item_code, warehouse, available_qty, conversion_factor = item.item_code,item.warehouse, item.actual_qty, item.conversion_factor or 1
            if item.stock_qty > available_qty:
                item.stock_qty = available_qty
                item.qty = item.stock_qty / flt(conversion_factor)
                item.amount = item.qty * item.rate
            available_qty -= item.stock_qty

        new_items = []
        #重新分派明细表显示的序（行)号
        idx = 1
        for item in items:
            if item.qty:    #删除无库存数量的明细行
                item.idx = idx
                new_items.append(item)
                idx += 1

        target_doc.items = new_items

    return target_doc
